#include "vector3d.h"

Vector3D vector3d_create(double x, double y, double z) {
    Vector3D v = {x, y, z};
    return v;
}

Vector3D vector3d_add(Vector3D a, Vector3D b) {
    return vector3d_create(a.x + b.x, a.y + b.y, a.z + b.z);
}

Vector3D vector3d_sub(Vector3D a, Vector3D b) {
    return vector3d_create(a.x - b.x, a.y - b.y, a.z - b.z);
}

Vector3D vector3d_scale(Vector3D v, double scalar) {
    return vector3d_create(v.x * scalar, v.y * scalar, v.z * scalar);
}

double vector3d_dot(Vector3D a, Vector3D b) {
    return a.x * b.x + a.y * b.y + a.z * b.z;
}

Vector3D vector3d_cross(Vector3D a, Vector3D b) {
    return vector3d_create(
        a.y * b.z - a.z * b.y,
        a.z * b.x - a.x * b.z,
        a.x * b.y - a.y * b.x
    );
}

double vector3d_magnitude(Vector3D v) {
    return sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}

Vector3D vector3d_normalize(Vector3D v) {
    double mag = vector3d_magnitude(v);
    if (mag < 1e-10) {
        return vector3d_zero();
    }
    return vector3d_scale(v, 1.0 / mag);
}

Vector3D vector3d_negate(Vector3D v) {
    return vector3d_create(-v.x, -v.y, -v.z);
}

Vector3D vector3d_zero() {
    return vector3d_create(0.0, 0.0, 0.0);
}

Vector3D vector3d_i() {
    return vector3d_create(1.0, 0.0, 0.0);
}

Vector3D vector3d_j() {
    return vector3d_create(0.0, 1.0, 0.0);
}

Vector3D vector3d_k() {
    return vector3d_create(0.0, 0.0, 1.0);
}

double vector3d_distance(Vector3D a, Vector3D b) {
    return vector3d_magnitude(vector3d_sub(a, b));
}

Vector3D vector3d_lerp(Vector3D a, Vector3D b, double t) {
    t = CLAMP(t, 0.0, 1.0);
    return vector3d_add(
        vector3d_scale(a, 1.0 - t),
        vector3d_scale(b, t)
    );
}

bool vector3d_equal(Vector3D a, Vector3D b, double tolerance) {
    return vector3d_distance(a, b) < tolerance;
}

void vector3d_print(const char* name, Vector3D v) {
    printf("%s: [%.6f, %.6f, %.6f]\n", name, v.x, v.y, v.z);
}
